package com.tchepannou.limbe.engine;

import com.tchepannou.limbe.*;
import com.tchepannou.limbe.mail.MailControllerContainer;
import com.tchepannou.limbe.web.ActionControllerContainer;

import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Framework engine
 *
 * @author Herve Tchepannou
 */
public class Engine
    implements Context,
               ServiceContext
{
    //-- Static Attribute
    private static final Logger LOG = Logger.getLogger (Engine.class.getName ());
    private static final Engine INSTANCE = new Engine ();
    //-- Attribute
    private String _basePackage;
    private String _loginURL = "/login";
    private ServletContext _servletContext;
    private List<Interceptor> _actionInterceptors = new ArrayList<Interceptor> ();
    private List<Interceptor> _mailInterceptors = new ArrayList<Interceptor> ();
    private List<Interceptor> _jobInterceptors = new ArrayList<Interceptor> ();
    private List<Interceptor> _messageInterceptors = new ArrayList<Interceptor> ();
    private Map<Class<? extends Service>, Service> _services = new HashMap<Class<? extends Service>, Service> ();
    private Class<? extends Util> _utilClass;
    private ActionControllerContainer _actionContainer = new ActionControllerContainer ();
    private MailControllerContainer _mailContainer = new MailControllerContainer ();
    //private JobControllerContainer _jobContainer = new JobControllerContainer ();
    //private MessageControllerContainer _messageContainer = new MessageControllerContainer ();
    //private Class<? extends ActionControllerWrapperResolver> _actionControllerResolver;
    private boolean _initialized;

    //-- Constructor
    private Engine ()
    {
    }

    //-- Public methods
    public static Engine getInstance ()
    {
        return INSTANCE;
    }

    public void init (ServletContext servletContext)
    {
        LOG.info ("Initializing");

        _servletContext = servletContext;

        /* Initialize the services */
        LOG.info ("Initializing Services");
        Context cc = this;
        for ( Service service: _services.values () )
        {
            LOG.info ("  Initializing " + service);
            service.init (this);
        }


        /* Containers */
        LOG.info ("Initializing Actions");
        _actionContainer.init (cc);
        _mailContainer.init (cc);

        _initialized = true;
        LOG.info ("Initialized");
    }

    public void destroy ()
    {
        LOG.info ("Destroying");

        for ( Service service: _services.values () )
        {
            service.destroy ();
        }

        _actionContainer.destroy ();
        _mailContainer.destroy ();

        _services.clear ();
        _actionInterceptors.clear ();
        _jobInterceptors.clear ();
        _mailInterceptors.clear ();
        _messageInterceptors.clear ();

        _initialized = false;

        LOG.info ("Destroyed");
    }

    public boolean isInitialized ()
    {
        return _initialized;
    }

    public Class<? extends Util> getUtilClass ()
    {
        return _utilClass;
    }

    public void setLoginURL (String loginURL)
    {
        this._loginURL = loginURL;
    }

    public void registerService (Class<? extends Service> type, Service service)
    {
        LOG.info ("Registering service: " + type.getName () + "=" + service);
        _services.put (type, service);
    }

    public void registerActionInterceptor (Interceptor interceptor)
    {
        LOG.info ("Registering Action Interceptor: " + interceptor);
        _actionInterceptors.add (interceptor);
    }

    public void registerMailInterceptor (Interceptor interceptor)
    {
        LOG.info ("Registering Mail Interceptor: " + interceptor);
        _mailInterceptors.add (interceptor);
    }

    public void registerJobInterceptor (Interceptor interceptor)
    {
        LOG.info ("Registering Job Interceptor: " + interceptor);
        _jobInterceptors.add (interceptor);
    }

    public void registerMessageInterceptor (Interceptor interceptor)
    {
        LOG.info ("Registering Message Interceptor: " + interceptor);
        _messageInterceptors.add (interceptor);
    }

    public void setBasePackage (String basePackage)
    {
        this._basePackage = basePackage;
    }

    public void setServletContext (ServletContext servletContext)
    {
        this._servletContext = servletContext;
    }

    public ActionControllerContainer getActionContainer ()
    {
        return _actionContainer;
    }

    public MailControllerContainer getMailContainer ()
    {
        return _mailContainer;
    }
    
    

    public void setUtilClass (Class<? extends Util> clazz)
    {
        _utilClass = clazz;
    }

    //-- Context methods
    @Override
    public <T extends Service> T findService (Class<T> type)
    {
        @SuppressWarnings ( "unchecked" )
        T t = ( T ) _services.get (type);
        return t;
    }

    @Override
    public List<Interceptor> getInterceptors ()
    {
        return null;
    }

    @Override
    public void setRollback (boolean rollback)
    {
    }

    @Override
    public boolean isRollback ()
    {
        return false;
    }

    @Override
    public Util createUtil ()
    {
        try
        {
            Util util = _utilClass != null
                ? _utilClass.newInstance ()
                : new Util ();
            util.setContainerContext (this);

            return util;
        }
        catch ( InstantiationException e )
        {
            throw new IllegalStateException ("Unable to instanciate " + _utilClass, e);
        }
        catch ( IllegalAccessException e )
        {
            throw new IllegalStateException ("Unable to instanciate " + _utilClass, e);
        }
    }

    //-- Getter/Setter
    @Override
    public ServletContext getServletContext ()
    {
        return _servletContext;
    }

    @Override
    public String getBasePackage ()
    {
        return _basePackage;
    }

    public List<Interceptor> getActionInterceptors ()
    {
        return _actionInterceptors;
    }

    public List<Interceptor> getMailInterceptors ()
    {
        return _mailInterceptors;
    }

    public List<Interceptor> getMessageInterceptors ()
    {
        return _messageInterceptors;
    }

    public List<Interceptor> getJobInterceptors ()
    {
        return _jobInterceptors;
    }

    public Map<Class<? extends Service>, Service> getServices ()
    {
        return _services;
    }

    public String getLoginURL ()
    {
        return _loginURL;
    }
}
